home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / Amiga_Mail_Vol2 / Archives / Plain / mj90 / ASCII / CollisionDetectV-25.ascii < prev    next >
Encoding:
Text File  |  1993-12-07  |  52.9 KB  |  1,539 lines

  1. (c)  Copyright 1990 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice,
  3. and  is provided "as is" without warranty of any kind, either express
  4. or implied.   The entire risk as to the use of this information is
  5. assumed by the user.
  6.  
  7. Collision Detection Between Animation Objects
  8.  
  9. by Ken Farinsky
  10.  
  11. Collision detection allows the system to manage Gel-to-Border and
  12. Gel-to-Gel collision handling for an application.  "Gels" are
  13. VSprite-based objects that may be displayed and moved about the
  14. Amiga display.  These objects include VSprites (Virtual Sprites),
  15. Bobs (Blitter Objects), and AnimObs (Animation Objects).  For a
  16. detailed discussion of collision detection between simple Gels
  17. (such as VSprites and Bobs), see the "Graphics: Sprites, Bobs and
  18. Animation" chapter in the ROM Kernel Manual: Libraries and
  19. Devices.
  20.  
  21. The basic premise of Amiga collision detection is to call a user
  22. supplied collision routine when two objects overlap.  This is
  23. complicated by two further enhancements.  First, borders are
  24. counted as objects and special-case processing of collisions is
  25. provided between Gels and the border.  Second, each Gel has two
  26. masks that indicate how pairs of objects will react when they
  27. collide.
  28.  
  29. Collision detection between objects such as VSprites and Bobs is
  30. conceptually very simple.  Each object is built upon a single
  31. underlying structure, the VSprite structure.  After the Gel has
  32. been added to the system, the DoCollision() routine scans the
  33. list of VSprites for overlapping objects and calls the
  34. appropriate user-supplied collision routine in the event of a
  35. collision.  Since there is a one-to-one correspondence between
  36. VSprites and objects, it is obvious which VSprite structure
  37. belongs to which object on the screen.
  38.  
  39. Animation Objects Are Not Simple Gels
  40.  
  41. Animation Objects contain multiple VSprite structures which are
  42. linked to form a larger object.  When the object is being
  43. animated, the system cycles through these underlying components,
  44. displaying each at the appropriate moment.  At any given point in
  45. time the system may be in the process of removing the last
  46. displayed component and adding in the next one.  During such a
  47. component switch, the system will have two VSprites added for a
  48. single object: one is in the process of being removed and one is
  49. in the process of being displayed.
  50.  
  51. Special Initialization Steps for Complex Gel Collision Detection
  52.  
  53. When setting-up a multi-component Gel, each underlying VSprite
  54. structure must be initialized for collision, as the system will
  55. not look to the others for more information.  An AnimOb's
  56. collision detection information need not be static.  The
  57. collision information can change from frame to frame in the same
  58. manner image data can change.  The example shows a special case,
  59. where all frames are similar enough that they have identical
  60. collision information.
  61.  
  62. The following fields in the VSprite structure must be properly
  63. initialized for system collision detection: HitMask, MeMask,
  64. BorderLine and CollMask.  HitMask and MeMask tell the system
  65. which collision routine to call when a collision is detected. 
  66. BorderLine and CollMask are "shadow masks" that are used to
  67. determine if this component overlaps any other object.  These
  68. values are set just as they would be for a single VSprite or a
  69. Bob.
  70.  
  71. Note that it is impossible for components of a single AnimOb's
  72. sequence to collide with one another.  However, in an AnimOb that
  73. contains multiple sequences, it is possible for a component in
  74. one sequence to collide with a component from a different
  75. sequence.  This can be prevented through careful selection of
  76. HitMask and MeMask values, or can be detected in the individual
  77. collision routines.
  78.  
  79. What Happens When Complex Gels Collide
  80.  
  81. Collisions between Animation Objects should be fairly simple to
  82. process.  The DoCollision() routine should examine all displayed
  83. objects for both overlap of objects and for correct interaction
  84. between the HitMask and MeMask, then call the appropriate
  85. collision routine.
  86.  
  87. Unfortunately, the DoCollision() routine does not ignore the
  88. previous AnimOb component, which is in the process of being
  89. removed from the display.  These components are moved by the
  90. system to a position well above and to the left of the visible
  91. display.  When the Gels are next drawn, the removed component
  92. will be moved off-screen, causing it to disappear from the
  93. display.  At the same time, the new component will be drawn
  94. on-screen.  This would not be a problem if the removed components
  95. did not overlap, however, all components that are being removed
  96. are positioned at the same off-screen location.  This means that
  97. they all overlap and collisions will occur between all pairs of
  98. components that are in the process of being removed.
  99.  
  100.  
  101. The BOBSAWAY Flag Comes to the Rescue
  102.  
  103. To handle collisions between pairs of AnimObs, the Gel-to-Gel
  104. collision routines must ignore the objects that are being
  105. removed.  There are two ways to handle this.  The first is to
  106. check for large negative position values in the X and Y variables
  107. of the VSprite structure.  This works, but is not the best way to
  108. check for removal.  The second, and preferred method, is to look
  109. at the flags of the associated Bob.  If the BOBSAWAY flag is set,
  110. then the bob is being removed and should not be used in the
  111. collision routines.  Note that this has been changed for 2.0,
  112. which will only look at active VSprites for collision detection.
  113.  
  114. The example code is made up of four files:
  115.  
  116. 1)    animtools.h               - include file necessary to use
  117. animtools.
  118. 2)    animtools_proto.h        - prototypes for animtools
  119. functions.
  120. 3)    animtools.c              - animtools functions.  These
  121. simplify the use of the animation 
  122.                                 sub-system.
  123. 4)    collide.c                     - example code.
  124.  
  125. The example code was published in the latest release of the ROM
  126. Kernel Manual: Libraries & Devices.  It has been updated and
  127. reprinted here.  The example can be compiled and linked using
  128. Lattice C with these commands:
  129.  
  130. lc -b1 -cfist -v -y -ocollide.o collide.c
  131. lc -b1 -cfist -v -y -oanimtools.o animtools.c
  132. blink from lib:c.o collide.o animtools.o library 
  133.     lib:lc.lib lib:amiga.lib to collide.
  134.  
  135.  
  136.  
  137.  
  138.  
  139. #ifndef GELTOOLS_H
  140. #define GELTOOLS_H
  141.  
  142. /* these data structures are used by the functions in animtools.c to
  143. ** allow for an easier interface to the animation system.
  144. */
  145.  
  146. /* data structure to hold information for a new vsprite.
  147. ** note that:
  148. **     NEWVSPRITE myNVS;
  149. ** is equivalent to:
  150. **     struct newVSprite myNVS;
  151. */
  152. typedef struct newVSprite
  153.     {
  154.     WORD           *nvs_Image;      /* image data for the vsprite   */
  155.     WORD           *nvs_ColorSet;   /* color array for the vsprite  */
  156.     SHORT           nvs_WordWidth;  /* width in words               */
  157.     SHORT           nvs_LineHeight; /* height in lines              */
  158.     SHORT           nvs_ImageDepth; /* depth of the image           */
  159.     SHORT           nvs_X;          /* initial x position           */
  160.     SHORT           nvs_Y;          /* initial y position           */
  161.     SHORT           nvs_Flags;      /* vsprite flags                */
  162.  
  163. /* THIS HAS CHANGED for amiga mail. **********************************
  164. **
  165. ** Add two lines to the NEWVSPRITE structure.
  166. ** This allows the created VSprite structures to be initialized with
  167. ** HitMask and MeMask information.
  168. */
  169.     USHORT          nvs_HitMask;    /* Hit mask.                    */
  170.     USHORT          nvs_MeMask;     /* Me mask.                     */
  171. /*
  172. ** END OF CHANGE for amiga mail.    **********************************
  173. */
  174.     } NEWVSPRITE;
  175.  
  176. /* data structure to hold information for a new bob.
  177. ** note that:
  178. **     NEWBOB myNBob;
  179. ** is equivalent to:
  180. **     struct newBob myNBob;
  181. */
  182. typedef struct newBob
  183.     {
  184.     WORD       *nb_Image;       /* image data for the bob       */
  185.     SHORT       nb_WordWidth;   /* width in words               */
  186.     SHORT       nb_LineHeight;  /* height in lines              */
  187.     SHORT       nb_ImageDepth;  /* depth of the image           */
  188.     SHORT       nb_PlanePick;   /* planes that get image data   */
  189.     SHORT       nb_PlaneOnOff;  /* unused planes to turn on     */
  190.     SHORT       nb_BFlags;      /* bob flags                    */
  191.     SHORT       nb_DBuf;        /* 1=double buf, 0=not          */
  192.     SHORT       nb_RasDepth;    /* depth of the raster          */
  193.     SHORT       nb_X;           /* initial x position           */
  194.     SHORT       nb_Y;           /* initial y position           */
  195.  
  196. /* THIS HAS CHANGED for amiga mail. **********************************
  197. **
  198. ** Add two lines to the NEWBOB structure.
  199. ** This is only used to pass the information to the VSprite structure
  200. ** in the makeBob() routine.
  201. */
  202.     USHORT      nb_HitMask;     /* Hit mask.                    */
  203.     USHORT      nb_MeMask;      /* Me mask.                     */
  204. /*
  205. ** END OF CHANGE for amiga mail.    **********************************
  206. */
  207.     } NEWBOB ;
  208.  
  209. /* data structure to hold information for a new animation component.
  210. ** note that:
  211. **     NEWANIMCOMP myNAC;
  212. ** is equivalent to:
  213. **     struct newAnimComp myNAC;
  214. */
  215. typedef struct newAnimComp
  216.     {
  217.     WORD  (*nac_Routine)(); /* routine called when Comp is displayed.   */
  218.     SHORT   nac_Xt;         /* initial delta offset position.           */
  219.     SHORT   nac_Yt;         /* initial delta offset position.           */
  220.     SHORT   nac_Time;       /* Initial Timer value.                     */
  221.     SHORT   nac_CFlags;     /* Flags for the Component.                 */
  222.     } NEWANIMCOMP;
  223.  
  224. /* data structure to hold information for a new animation sequence.
  225. ** note that:
  226. **     NEWANIMSEQ myNAS;
  227. ** is equivalent to:
  228. **     struct newAnimSeq myNAS;
  229. */
  230. typedef struct newAnimSeq
  231.     {
  232.     struct AnimOb  *nas_HeadOb; /* common Head of Object.               */
  233.     WORD   *nas_Images;         /* array of Comp image data             */
  234.     SHORT  *nas_Xt;             /* arrays of initial offsets.           */
  235.     SHORT  *nas_Yt;             /* arrays of initial offsets.           */
  236.     SHORT  *nas_Times;          /* array of Initial Timer value.        */
  237.     WORD (**nas_Routines)();    /* Array of fns called when comp drawn  */
  238.     SHORT   nas_CFlags;         /* Flags for the Component.             */
  239.     SHORT   nas_Count;          /* Num Comps in seq (= arrays size)     */
  240.  
  241. /* THIS HAS CHANGED for amiga mail. **********************************
  242. **
  243. ** Delete two lines from the NEWANIMSEQ structure.
  244. ** These are removed becaues the information is now contained in the
  245. ** NEWBOB and NEWVSPRITE structures.
  246. **
  247. **  SHORT   nas_HitMask;
  248. **  SHORT   nas_MeMask;
  249. **
  250. ** END OF CHANGE for amiga mail.    **********************************
  251. */
  252.     SHORT   nas_SingleImage;    /* one (or count) images.               */
  253.     } NEWANIMSEQ;
  254.  
  255. #endif
  256.  
  257.  
  258.  
  259. =====================================================================
  260. =====================================================================
  261.  
  262. /* animtools_proto.h */
  263.  
  264. struct GelsInfo *setupGelSys(struct RastPort *rPort, BYTE reserved);
  265. VOID cleanupGelSys(struct GelsInfo *gInfo, struct RastPort *rPort);
  266.  
  267. struct VSprite *makeVSprite(NEWVSPRITE *nVSprite);
  268. struct Bob *makeBob(NEWBOB *nBob);
  269. struct AnimComp *makeComp(NEWBOB *nBob, NEWANIMCOMP *nAnimComp);
  270. struct AnimComp *makeSeq(NEWBOB *nBob, NEWANIMSEQ *nAnimSeq);
  271.  
  272. VOID freeVSprite(struct VSprite *vsprite);
  273. VOID freeBob(struct Bob *bob, LONG rasdepth);
  274. VOID freeComp(struct AnimComp *myComp, LONG rasdepth);
  275. VOID freeSeq(struct AnimComp *headComp, LONG rasdepth);
  276. VOID freeOb(struct AnimOb *headOb, LONG rasdepth);
  277.  
  278.  
  279. =====================================================================
  280. =====================================================================
  281.  
  282. /* animtools.c 19oct89 original code by Dave Lucas.
  283. ** rework by (CATS)
  284. **
  285. ** This file is a collection of tools which are used with the VSprite, Bob
  286. ** and Animation system software. It is intended as a useful EXAMPLE, and
  287. ** while it shows what must be done, it is not the only way to do it.
  288. ** If Not Enough Memory, or error return, each cleans up after itself
  289. ** before returning.
  290. **
  291. ** NOTE:  these routines assume a very specific structure to the
  292. ** gel lists.  make sure that you use the correct pairs together
  293. ** (i.e. makeOb()/freeOb(), etc.)
  294. **
  295. ** lattice c 5.04
  296. ** lc -b1 -cfist -v -y -oanimtools.o animtools.c
  297. */
  298.  
  299. #include <exec/types.h>
  300. #include <exec/memory.h>
  301. #include <graphics/gfx.h>
  302. #include <graphics/gels.h>
  303. #include <graphics/clip.h>
  304. #include <graphics/rastport.h>
  305. #include <graphics/view.h>
  306. #include <graphics/gfxbase.h>
  307.  
  308. /* THIS HAS CHANGED for amiga mail. **********************************
  309. **
  310. ** In the RKM it was assumed that animtools stuff was in a different
  311. ** directory from the example program.
  312. **
  313. **      #include "/animtools/animtools.h"
  314. **      #include "/animtools/animtools_proto.h"
  315. **
  316. ** Now they are in the same directory as the example:
  317. **
  318. ** END OF CHANGE for amiga mail.    **********************************
  319. */
  320. #include "animtools.h"
  321. #include "animtools_proto.h"
  322.  
  323. #include <proto/all.h>
  324.  
  325. /*-------------------------------------------------------------
  326. ** setup the gels system.  After this call is made you can use
  327. ** vsprites, bobs, anim comps, and anim obs.
  328. **
  329. ** note that this links the GelsInfo structure into the rast port,
  330. ** and calls InitGels().
  331. **
  332. ** all resources are properly freed on failure.
  333. **
  334. ** It uses information in your RastPort structure to establish
  335. ** boundary collision defaults at the outer edges of the raster.
  336. **
  337. ** This routine sets up for everything - collision detection and all.
  338. **
  339. ** You must already have run LoadView before ReadyGelSys is called.
  340. */
  341. struct GelsInfo *setupGelSys(struct RastPort *rPort, BYTE reserved)
  342. {
  343. struct GelsInfo *gInfo;
  344. struct VSprite  *vsHead;
  345. struct VSprite  *vsTail;
  346.  
  347. if (NULL != (gInfo =
  348.     (struct GelsInfo *)AllocMem((LONG)sizeof(struct GelsInfo), MEMF_CLEAR)))
  349.     {
  350.     if (NULL != (gInfo->nextLine =
  351.         (WORD *)AllocMem((LONG)sizeof(WORD) * 8, MEMF_CLEAR)))
  352.         {
  353.         if (NULL != (gInfo->lastColor =
  354.             (WORD **)AllocMem((LONG)sizeof(LONG) * 8, MEMF_CLEAR)))
  355.             {
  356.             if (NULL != (gInfo->collHandler =
  357.                 (struct collTable *)AllocMem((LONG)sizeof(struct collTable),
  358.                     MEMF_CLEAR)))
  359.                 {
  360.                 if (NULL != (vsHead = (struct VSprite *)AllocMem(
  361.                     (LONG)sizeof(struct VSprite), MEMF_CLEAR)))
  362.                     {
  363.                     if (NULL != (vsTail = (struct VSprite *)AllocMem(
  364.                         (LONG)sizeof(struct VSprite), MEMF_CLEAR)))
  365.                         {
  366.                         gInfo->sprRsrvd   = reserved;
  367.  
  368. /* THIS HAS CHANGED for amiga mail. **********************************
  369. **
  370. ** In the RKM leftmost and topmost were set to zero.
  371. **
  372. **                      gInfo->leftmost   = 0;
  373. **                      gInfo->topmost    = 0;
  374. **
  375. ** This has been changed to one to better keep items inside the boundaries
  376. ** of the display.
  377. */
  378.                         gInfo->leftmost   = 1;
  379.                         gInfo->topmost    = 1;
  380. /*
  381. ** END OF CHANGE for amiga mail.    **********************************
  382. */
  383.  
  384.                         gInfo->rightmost  =
  385.                             (rPort->BitMap->BytesPerRow << 3) - 1;
  386.                         gInfo->bottommost = rPort->BitMap->Rows - 1;
  387.  
  388.                         rPort->GelsInfo = gInfo;
  389.  
  390.                         InitGels(vsHead, vsTail, gInfo);
  391.  
  392.                         return(gInfo);
  393.                         }
  394.                     FreeMem(vsHead, (LONG)sizeof(*vsHead));
  395.                     }
  396.                 FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable));
  397.                 }
  398.             FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8);
  399.             }
  400.         FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8);
  401.         }
  402.     FreeMem(gInfo, (LONG)sizeof(*gInfo));
  403.     }
  404. return(NULL);
  405. }
  406.  
  407. /*-------------------------------------------------------------
  408. ** free all of the stuff allocated by setupGelSys().
  409. ** only call this routine if setupGelSys() returned successfully.
  410. ** the GelsInfo structure is the one returned by setupGelSys().
  411. **
  412. ** It also unlinks the GelsInfo from the RastPort.
  413. */
  414. VOID cleanupGelSys(struct GelsInfo *gInfo, struct RastPort *rPort)
  415. {
  416. rPort->GelsInfo = NULL;
  417.  
  418. FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable));
  419. FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8);
  420. FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8);
  421. FreeMem(gInfo->gelHead, (LONG)sizeof(struct VSprite));
  422. FreeMem(gInfo->gelTail, (LONG)sizeof(struct VSprite));
  423. FreeMem(gInfo, (LONG)sizeof(*gInfo));
  424. }
  425.  
  426. /*-------------------------------------------------------------
  427. ** create a VSprite from the information given in nVSprite.
  428. ** use freeVSprite() to free this gel.
  429. */
  430. struct VSprite *makeVSprite(NEWVSPRITE *nVSprite)
  431. {
  432. struct VSprite *vsprite;
  433. LONG            line_size;
  434. LONG            plane_size;
  435.  
  436. line_size = (LONG)sizeof(WORD) * nVSprite->nvs_WordWidth;
  437. plane_size = line_size * nVSprite->nvs_LineHeight;
  438.  
  439. if (NULL != (vsprite =
  440.     (struct VSprite *)AllocMem((LONG)sizeof(struct VSprite), MEMF_CLEAR)))
  441.     {
  442.     if (NULL != (vsprite->BorderLine =
  443.         (WORD *)AllocMem(line_size, MEMF_CHIP)))
  444.         {
  445.         if (NULL != (vsprite->CollMask =
  446.             (WORD *)AllocMem(plane_size, MEMF_CHIP)))
  447.             {
  448.             vsprite->Y          = nVSprite->nvs_Y;
  449.             vsprite->X          = nVSprite->nvs_X;
  450.             vsprite->Flags      = nVSprite->nvs_Flags;
  451.             vsprite->Width      = nVSprite->nvs_WordWidth;
  452.             vsprite->Depth      = nVSprite->nvs_ImageDepth;
  453.             vsprite->Height     = nVSprite->nvs_LineHeight;
  454.  
  455. /* THIS HAS CHANGED for amiga mail. **********************************
  456. **
  457. ** In the RKM, the vsprite HitMask and MeMask were set to an arbitrary
  458. ** value (it was assumed that the programmer would later patch these
  459. ** values if collision detection was required!)
  460. **
  461. **          vsprite->MeMask     = 1;
  462. **          vsprite->HitMask    = 1;
  463. **
  464. ** Here, we have changed the NEWVSPRITE structure to contain these
  465. ** values, so this routine can set-up both of them.
  466. */
  467.             vsprite->MeMask     = nVSprite->nvs_MeMask;
  468.             vsprite->HitMask    = nVSprite->nvs_HitMask;
  469. /*
  470. ** END OF CHANGE for amiga mail.    **********************************
  471. */
  472.  
  473.             vsprite->ImageData  = nVSprite->nvs_Image;
  474.             vsprite->SprColors  = nVSprite->nvs_ColorSet;
  475.             vsprite->PlanePick  = 0x00;
  476.             vsprite->PlaneOnOff = 0x00;
  477.  
  478.             InitMasks(vsprite);
  479.             return(vsprite);
  480.             }
  481.         FreeMem(vsprite->BorderLine, line_size);
  482.         }
  483.     FreeMem(vsprite, (LONG)sizeof(*vsprite));
  484.     }
  485. return(NULL);
  486. }
  487.  
  488. /*-------------------------------------------------------------
  489. ** create a Bob from the information given in nBob.
  490. ** use freeBob() to free this gel.
  491. **
  492. ** A VSprite is created for this bob.
  493. ** This routine properly allocates all double buffered information
  494. ** if it is required.
  495. */
  496. struct Bob *makeBob(NEWBOB *nBob)
  497. {
  498. struct Bob         *bob;
  499. struct VSprite     *vsprite;
  500. NEWVSPRITE          nVSprite ;
  501. LONG                rassize;
  502.  
  503. rassize = (LONG)sizeof(UWORD) *
  504.             nBob->nb_WordWidth * nBob->nb_LineHeight * nBob->nb_RasDepth;
  505.  
  506. if (NULL != (bob =
  507.     (struct Bob *)AllocMem((LONG)sizeof(struct Bob), MEMF_CLEAR)))
  508.     {
  509.     if (NULL != (bob->SaveBuffer = (WORD *)AllocMem(rassize, MEMF_CHIP)))
  510.         {
  511.         nVSprite.nvs_WordWidth  = nBob->nb_WordWidth;
  512.         nVSprite.nvs_LineHeight = nBob->nb_LineHeight;
  513.         nVSprite.nvs_ImageDepth = nBob->nb_ImageDepth;
  514.         nVSprite.nvs_Image      = nBob->nb_Image;
  515.         nVSprite.nvs_X          = nBob->nb_X;
  516.         nVSprite.nvs_Y          = nBob->nb_Y;
  517.         nVSprite.nvs_ColorSet   = NULL;
  518.         nVSprite.nvs_Flags      = nBob->nb_BFlags;
  519.  
  520. /* THIS HAS CHANGED for amiga mail. **********************************
  521. **
  522. ** The structure of the program has been changed to pass the values
  523. ** of the HitMask and the MeMask down to the VSprite structure.
  524. ** Push the values into the NEWVSPRITE structure for use in
  525. ** makeVSprite().
  526. */
  527.         nVSprite.nvs_MeMask     = nBob->nb_MeMask;
  528.         nVSprite.nvs_HitMask    = nBob->nb_HitMask;
  529. /*
  530. ** END OF CHANGE for amiga mail.    **********************************
  531. */
  532.  
  533.         if ((vsprite = makeVSprite(&nVSprite)) != NULL)
  534.             {
  535.             vsprite->PlanePick = nBob->nb_PlanePick;
  536.             vsprite->PlaneOnOff = nBob->nb_PlaneOnOff;
  537.  
  538.             vsprite->VSBob   = bob;
  539.             bob->BobVSprite  = vsprite;
  540.             bob->ImageShadow = vsprite->CollMask;
  541.             bob->Flags       = 0;
  542.             bob->Before      = NULL;
  543.             bob->After       = NULL;
  544.             bob->BobComp     = NULL;
  545.  
  546.             if (nBob->nb_DBuf)
  547.                 {
  548.                 if (NULL != (bob->DBuffer = (struct DBufPacket *)AllocMem(
  549.                     (LONG)sizeof(struct DBufPacket), MEMF_CLEAR)))
  550.                     {
  551.                     if (NULL != (bob->DBuffer->BufBuffer =
  552.                         (WORD *)AllocMem(rassize, MEMF_CHIP)))
  553.                         {
  554.                         return(bob);
  555.                         }
  556.                     FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket));
  557.                     }
  558.                 }
  559.             else
  560.                 {
  561.                 bob->DBuffer = NULL;
  562.                 return(bob);
  563.                 }
  564.  
  565.             freeVSprite(vsprite);
  566.             }
  567.         FreeMem(bob->SaveBuffer, rassize);
  568.         }
  569.     FreeMem(bob, (LONG)sizeof(*bob));
  570.     }
  571. return(NULL);
  572. }
  573.  
  574. /*-------------------------------------------------------------
  575. ** create a Animation Component from the information given in nAnimComp
  576. ** and nBob.
  577. ** use freeComp() to free this gel.
  578. **
  579. ** makeComp calls makeBob(), and links the bob into a AnimComp.
  580. */
  581. struct AnimComp *makeComp(NEWBOB *nBob, NEWANIMCOMP *nAnimComp)
  582. {
  583. struct Bob      *compBob;
  584. struct AnimComp *aComp;
  585.  
  586. if ((aComp = AllocMem((LONG)sizeof(struct AnimComp),MEMF_CLEAR)) != NULL)
  587.     {
  588.     if ((compBob = makeBob(nBob)) != NULL)
  589.         {
  590.         compBob->After   = NULL;  /* Caller can deal with these later. */
  591.         compBob->Before  = NULL;
  592.         compBob->BobComp = aComp;   /* Link 'em up. */
  593.  
  594.         aComp->AnimBob      = compBob;
  595.         aComp->TimeSet      = nAnimComp->nac_Time; /* Num ticks active. */
  596.         aComp->YTrans       = nAnimComp->nac_Yt; /* Offset rel to HeadOb */
  597.         aComp->XTrans       = nAnimComp->nac_Xt;
  598.         aComp->AnimCRoutine = nAnimComp->nac_Routine;
  599.         aComp->Flags        = nAnimComp->nac_CFlags;
  600.         aComp->Timer        = 0;
  601.         aComp->NextSeq      = NULL;
  602.         aComp->PrevSeq      = NULL;
  603.         aComp->NextComp     = NULL;
  604.         aComp->PrevComp     = NULL;
  605.         aComp->HeadOb       = NULL;
  606.  
  607.         return(aComp);
  608.         }
  609.     FreeMem(aComp, (LONG)sizeof(struct AnimComp));
  610.     }
  611. return(NULL);
  612. }
  613.  
  614. /*-------------------------------------------------------------
  615. ** create an Animation Sequence from the information given in nAnimSeq
  616. ** and nBob.
  617. ** use freeSeq() to free this gel.
  618. **
  619. ** this routine creates a linked list of animation components which
  620. ** make up the animation sequence.
  621. **
  622. ** It links them all up, making a circular list of the PrevSeq
  623. ** and NextSeq pointers. That is to say, the first component of the
  624. ** sequences' PrevSeq points to the last component; the last component of
  625. ** the sequences' NextSeq points back to the first component.
  626. **
  627. ** If dbuf is on, the underlying Bobs'll be set up for double buffering.
  628. ** If singleImage is non-zero, the pImages pointer is assumed to point to
  629. ** an array of only one image, instead of an array of 'count' images, and
  630. ** all Bobs will use the same image.
  631. */
  632. struct AnimComp *makeSeq(NEWBOB *nBob, NEWANIMSEQ *nAnimSeq)
  633. {
  634. int seq;
  635. struct AnimComp *firstCompInSeq = NULL;
  636. struct AnimComp *seqComp = NULL;
  637. struct AnimComp *lastCompMade = NULL;
  638. LONG image_size;
  639. NEWANIMCOMP nAnimComp;
  640.  
  641. /* get the initial image.  this is the only image that is used
  642. ** if nAnimSeq->nas_SingleImage is non-zero.
  643. */
  644. nBob->nb_Image = nAnimSeq->nas_Images;
  645. image_size = nBob->nb_LineHeight * nBob->nb_ImageDepth * nBob->nb_WordWidth;
  646.  
  647. /* for each comp in the sequence */
  648. for (seq = 0; seq < nAnimSeq->nas_Count; seq++)
  649.     {
  650.     nAnimComp.nac_Xt        = *(nAnimSeq->nas_Xt + seq);
  651.     nAnimComp.nac_Yt        = *(nAnimSeq->nas_Yt + seq);
  652.     nAnimComp.nac_Time      = *(nAnimSeq->nas_Times + seq);
  653.     nAnimComp.nac_Routine   = nAnimSeq->nas_Routines[seq];
  654.     nAnimComp.nac_CFlags    = nAnimSeq->nas_CFlags;
  655.  
  656.     if ((seqComp = makeComp(nBob, &nAnimComp)) == NULL)
  657.         {
  658.         if (firstCompInSeq != NULL)
  659.             freeSeq(firstCompInSeq, (LONG)nBob->nb_RasDepth);
  660.         return(NULL);
  661.         }
  662.  
  663. /* THIS HAS CHANGED for amiga mail. **********************************
  664. **
  665. ** Remove these two lines from the RKM.  This is because we are now
  666. ** passing the HitMask and MeMask directly down to the VSprite structure.
  667. ** NOTE that the deleted technique only sets up the two values for one
  668. ** VSprite in the AnimComp.  The new technique (used in this example)
  669. ** correctly does the set-up of all the VSprites in the AnimComp.
  670. **
  671. **  seqComp->AnimBob->BobVSprite->HitMask = nAnimSeq->nas_HitMask;
  672. **  seqComp->AnimBob->BobVSprite->MeMask = nAnimSeq->nas_MeMask;
  673. **
  674. ** END OF CHANGE for amiga mail.    **********************************
  675. */
  676.     seqComp->HeadOb = nAnimSeq->nas_HeadOb;
  677.  
  678.     /* Make a note of where the first component is. */
  679.     if (firstCompInSeq == NULL)
  680.         firstCompInSeq = seqComp;
  681.  
  682.     /* link the component into the list */
  683.     if (lastCompMade != NULL)
  684.         lastCompMade->NextSeq = seqComp;
  685.  
  686.     seqComp->NextSeq = NULL;
  687.     seqComp->PrevSeq = lastCompMade;
  688.     lastCompMade = seqComp;
  689.  
  690.     /* If nAnimSeq->nas_SingleImage is zero,
  691.     ** the image array has nAnimSeq->nas_Count images.
  692.     */
  693.     if (!nAnimSeq->nas_SingleImage)
  694.         nBob->nb_Image += image_size;
  695.     }
  696. /* On The last component in the sequence, set Next/Prev to make
  697. ** the linked list a loop of components.
  698. */
  699. lastCompMade->NextSeq = firstCompInSeq;
  700. firstCompInSeq->PrevSeq = lastCompMade;
  701.  
  702. return(firstCompInSeq);
  703. }
  704.  
  705. /*-------------------------------------------------------------
  706. ** free the data created by makeVSprite()
  707. **
  708. ** assumes images deallocated elsewhere.
  709. */
  710. VOID freeVSprite(struct VSprite *vsprite)
  711. {
  712. LONG    line_size;
  713. LONG    plane_size;
  714.  
  715. line_size = (LONG)sizeof(WORD) * vsprite->Width;
  716. plane_size = line_size * vsprite->Height;
  717.  
  718. FreeMem(vsprite->BorderLine, line_size);
  719. FreeMem(vsprite->CollMask, plane_size);
  720.  
  721. FreeMem(vsprite, (LONG)sizeof(*vsprite));
  722. }
  723.  
  724. /*-------------------------------------------------------------
  725. ** free the data created by makeBob()
  726. **
  727. ** it's important that rasdepth match the depth you
  728. ** passed to makeBob() when this gel was made.
  729. ** assumes images deallocated elsewhere.
  730. */
  731. VOID freeBob(struct Bob *bob, LONG rasdepth)
  732. {
  733. LONG    rassize;
  734.  
  735. rassize =  (LONG)sizeof(UWORD) *
  736.         bob->BobVSprite->Width * bob->BobVSprite->Height * rasdepth;
  737.  
  738. if (bob->DBuffer != NULL)
  739.     {
  740.     FreeMem(bob->DBuffer->BufBuffer, rassize);
  741.     FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket));
  742.     }
  743. FreeMem(bob->SaveBuffer, rassize);
  744. freeVSprite(bob->BobVSprite);
  745. FreeMem(bob, (LONG)sizeof(*bob));
  746. }
  747.  
  748. /*-------------------------------------------------------------
  749. ** free the data created by makeComp()
  750. **
  751. ** it's important that rasdepth match the depth you
  752. ** passed to makeComp() when this gel was made.
  753. ** assumes images deallocated elsewhere.
  754. */
  755. VOID freeComp(struct AnimComp *myComp, LONG rasdepth)
  756. {
  757. freeBob(myComp->AnimBob, rasdepth);
  758. FreeMem(myComp, (LONG)sizeof(struct AnimComp));
  759. }
  760.  
  761. /*-------------------------------------------------------------
  762. ** free the data created by makeSeq()
  763. **
  764. ** Complimentary to makeSeq(), this routine goes through the NextSeq
  765. ** pointers and frees the Components
  766. **
  767. ** This routine only goes forward through the list, and so
  768. ** it must be passed the first component in the sequence, or the sequence
  769. ** must be circular (which is guaranteed if you use makeSeq()).
  770. **
  771. ** it's important that rasdepth match the depth you
  772. ** passed to makeSeq() when this gel was made.
  773. ** assumes images deallocated elsewhere.
  774. */
  775. VOID freeSeq(struct AnimComp *headComp, LONG rasdepth)
  776. {
  777. struct AnimComp *curComp;
  778. struct AnimComp *nextComp;
  779.  
  780. /* this is freeing a loop of AnimComps, hooked together by the
  781. ** NextSeq and PrevSeq pointers.
  782. */
  783.  
  784. /* break the NextSeq loop, so we get a NULL at the end of the list. */
  785. headComp->PrevSeq->NextSeq = NULL;
  786.  
  787. curComp = headComp;         /* get the start of the list */
  788. while (curComp != NULL)
  789.     {
  790.     nextComp = curComp->NextSeq;
  791.     freeComp(curComp, rasdepth);
  792.     curComp = nextComp;
  793.     }
  794. }
  795.  
  796. /*-------------------------------------------------------------
  797. ** free an animation object (list of sequences).
  798. **
  799. ** freeOb() goes through the NextComp pointers, starting at the AnimObs'
  800. ** HeadComp, and frees every sequence.
  801. ** it only goes forward. It then frees the Object itself.
  802. ** assumes images deallocated elsewhere.
  803. */
  804. VOID freeOb(struct AnimOb *headOb, LONG rasdepth)
  805. {
  806. struct AnimComp *curSeq;
  807. struct AnimComp *nextSeq;
  808.  
  809. curSeq = headOb->HeadComp;          /* get the start of the list */
  810. while (curSeq != NULL)
  811.     {
  812.     nextSeq = curSeq->NextComp;
  813.     freeSeq(curSeq, rasdepth);
  814.     curSeq = nextSeq;
  815.     }
  816.  
  817. FreeMem(headOb, (LONG)sizeof(struct AnimOb));
  818. }
  819.  
  820.  
  821. =====================================================================
  822. =====================================================================
  823.  
  824.  
  825. /* collide.c */
  826. /* This is an example that shows how to do collision detection between
  827. ** multiple animation objects and between animation objects and the border.
  828. **
  829. ** Lattice C 5.04
  830. ** lc -b1 -cfist -v -y -ocollide.o collide.c
  831. ** lc -b1 -cfist -v -y -oanimtools.o animtools.c
  832. ** blink from lib:c.o collide.o animtools.o
  833. **       library lib:lc.lib lib:amiga.lib to collide
  834. */
  835. #include <exec/types.h>
  836. #include <intuition/intuition.h>
  837. #include <graphics/gels.h>
  838. #include <graphics/collide.h>
  839. #include <exec/memory.h>
  840. #include <libraries/dos.h>
  841.  
  842. #include "animtools.h"
  843. #include "animtools_proto.h"
  844.  
  845. #include <stdlib.h>
  846. #include <stdio.h>
  847. #include <proto/all.h>
  848. int CXBRK(void) { return(0); }
  849.  
  850. /* prototypes for functions in this file */
  851. VOID __stdargs __saveds hit_routine(struct VSprite *vs1,struct VSprite *vs2);
  852. VOID __stdargs __saveds bounceWall(struct VSprite *vs1,LONG borderflags);
  853. struct AnimOb *setupBoing(SHORT dbufing);
  854. VOID runAnimation(struct Window *win, SHORT dbufing,
  855.                   struct AnimOb **animKey, struct BitMap **myBitMaps);
  856. LONG setupPlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height);
  857. struct BitMap **setupBitMaps(LONG depth, LONG width, LONG height);
  858. VOID freePlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height);
  859. VOID freeBitMaps(struct BitMap **myBitMaps,
  860.                     LONG depth, LONG width, LONG height);
  861. struct GelsInfo *setupDisplay(struct Window **win, SHORT dbufing,
  862.                               struct BitMap **myBitMaps);
  863. VOID drawGels(struct Window *win, struct AnimOb **animKey,
  864.               SHORT dbufing, WORD *toggleFrame, struct BitMap **myBitMaps);
  865.  
  866. #define RBMWIDTH  320
  867. #define RBMHEIGHT 200
  868. #define RBMDEPTH    4
  869.  
  870. struct NewScreen ns =
  871.     {
  872.     0, 0, 320, 200, 2, 0, 1, NULL,
  873.     CUSTOMSCREEN, NULL, "Collision With AnimObs", NULL, NULL
  874.     };
  875. struct NewWindow nw =
  876.     {
  877.     50, 50, 220, 100, -1, -1, CLOSEWINDOW,
  878.     WINDOWCLOSE | RMBTRAP, NULL, NULL, "Close Window to Stop", NULL,
  879.     NULL, 150, 100, 150, 100, CUSTOMSCREEN
  880.     };
  881.  
  882. struct IntuitionBase *IntuitionBase = NULL;
  883. struct GfxBase       *GfxBase       = NULL;
  884.  
  885. int return_code;
  886.  
  887. /* these give the number of frames (COUNT), size (HEIGHT, WIDTH, DEPTH),
  888. ** and word width (WWIDTH) of the animated object.
  889. */
  890. #define BOING_COUNT     6
  891. #define BOING_HEIGHT    25
  892. #define BOING_WIDTH     32
  893. #define BOING_DEPTH      1
  894. #define BOING_WWIDTH    ((BOING_WIDTH + 15) / 16)
  895.  
  896. /* these are the IDs for the system to use for the three objects.
  897. ** these numbers will be used for the collision detection system.
  898. **
  899. ** Do not use zero (0), as it is reserved by the collision system
  900. ** for border hits (see graphics/collide.h, BORDERHIT.)
  901. */
  902. #define BOING_1     2
  903. #define BOING_2     3
  904. #define BOING_3     4
  905.  
  906. /* these are the number of counts that each frame is displayed.
  907. ** they are all one, so each frame is displayed once then the
  908. ** animation system will move on to the next in the sequence
  909. */
  910. SHORT boing3Times[BOING_COUNT] = { 1, 1, 1, 1, 1, 1 };
  911.  
  912. /* these are all set to zero as we do not want anything added
  913. ** to the X and Y positions using ring motion control.
  914. ** all movement is done using the acceleration and velocity
  915. ** values.
  916. */
  917. SHORT boing3YTranses[BOING_COUNT] = { 0, 0, 0, 0, 0, 0 };
  918. SHORT boing3XTranses[BOING_COUNT] = { 0, 0, 0, 0, 0, 0 };
  919.  
  920. /* no special routines to call when each anim comp is displayed */
  921. WORD (*boing3CRoutines[BOING_COUNT])(struct AnimComp *) =
  922.     { NULL, NULL, NULL, NULL, NULL, NULL };
  923.  
  924. UWORD __chip boing3Image[BOING_COUNT][BOING_WWIDTH * BOING_HEIGHT * BOING_DEPTH]
  925. =
  926.     {
  927.     /*----- bitmap Boing, frame 0:  w = 32, h = 25 ------ */
  928.         {
  929.         0x0023, 0x0000,  0x004E, 0x3000,  0x00E3, 0x3A00,  0x03C3, 0xC900,
  930.         0x0787, 0x8780,  0x108F, 0x8700,  0x31F7, 0x8790,  0x61F0, 0x4790,
  931.         0x63E0, 0xFB90,  0x43E0, 0xF848,  0x3BC0, 0xF870,  0x3801, 0xF870,
  932.         0x383D, 0xF070,  0x387E, 0x1070,  0x387C, 0x0EE0,  0xD87C, 0x1F10,
  933.         0x467C, 0x1E10,  0x479C, 0x1E30,  0x6787, 0x3E20,  0x0787, 0xCC60,
  934.         0x0F0F, 0x8700,  0x048F, 0x0E00,  0x0277, 0x1C00,  0x0161, 0xD800,
  935.         0x0027, 0x2000,
  936.         },
  937.     /*----- bitmap Boing, frame 1:  w = 32, h = 25 ------ */
  938.         {
  939.         0x0031, 0x8000,  0x0107, 0x1800,  0x00F0, 0x1900,  0x09E1, 0xEC80,
  940.         0x13C1, 0xE340,  0x1803, 0xE380,  0x387B, 0xC390,  0x30F8, 0x01D0,
  941.         0x70F8, 0x3DC0,  0xE1F0, 0x3E08,  0x9DF0, 0x7C30,  0x9E30, 0x7C30,
  942.         0x9E1C, 0x7C30,  0x1C1F, 0x9C30,  0x1C1F, 0x0630,  0x7C1F, 0x0780,
  943.         0x623F, 0x0798,  0x63DE, 0x0F10,  0x23C1, 0x0F20,  0x33C3, 0xEE20,
  944.         0x0BC3, 0xC380,  0x0647, 0xC700,  0x023F, 0x8E00,  0x0130, 0xF800,
  945.         0x0033, 0x8000,
  946.         },
  947.     /*----- bitmap Boing, frame 2:  w = 32, h = 25 ------ */
  948.         {
  949.         0x0019, 0xC000,  0x0103, 0x8800,  0x0278, 0x8D00,  0x0CF0, 0xFE80,
  950.         0x11F0, 0xF140,  0x0E60, 0xF1E0,  0x1C39, 0xF0C0,  0x1C3E, 0x30C0,
  951.         0x387E, 0x0CE0,  0xF87C, 0x1F28,  0x8C7C, 0x1F18,  0x8F3C, 0x1F18,
  952.         0x8F06, 0x1E18,  0x8F07, 0xDE18,  0x8F07, 0xC018,  0x6E0F, 0xC1C0,
  953.         0x300F, 0x83C8,  0x31EF, 0x8390,  0x31F0, 0x8780,  0x11E0, 0xF720,
  954.         0x11E1, 0xF1C0,  0x0B61, 0xE300,  0x071B, 0xC600,  0x0138, 0x6C00,
  955.         0x0031, 0x8000,
  956.         },
  957.     /*----- bitmap Boing, frame 3:  w = 32, h = 25 ------ */
  958.         {
  959.         0x001C, 0xE000,  0x01B1, 0xCC00,  0x031C, 0xC500,  0x0C3C, 0x3680,
  960.         0x1878, 0x7840,  0x2F70, 0x78E0,  0x0E08, 0x7860,  0x1E0F, 0xB860,
  961.         0x1C1F, 0x0460,  0xBC1F, 0x07B0,  0xC43F, 0x0788,  0xC7FE, 0x0788,
  962.         0xC7C0, 0x0F88,  0xC781, 0xEF88,  0xC783, 0xF118,  0x2783, 0xE0E8,
  963.         0x3983, 0xE1E0,  0x3863, 0xE1C0,  0x1878, 0xC1C0,  0x3878, 0x3380,
  964.         0x10F0, 0x78C0,  0x0B70, 0xF180,  0x0588, 0xE200,  0x009E, 0x2400,
  965.         0x0018, 0xC000,
  966.         },
  967.     /*----- bitmap Boing, frame 4:  w = 32, h = 25 ------ */
  968.         {
  969.         0x000E, 0x6000,  0x00F8, 0xE400,  0x030F, 0xE600,  0x061E, 0x1300,
  970.         0x0C3E, 0x1C80,  0x27FC, 0x1C60,  0x0784, 0x3C60,  0x4F07, 0xFE20,
  971.         0x8F07, 0xC230,  0x1E0F, 0xC1F0,  0x620F, 0x83C8,  0x61CF, 0x83C8,
  972.         0x61E1, 0x83C8,  0x63E0, 0x63C8,  0x63E0, 0xF9C8,  0x03E0, 0xF878,
  973.         0x1DC0, 0xF860,  0x1C21, 0xF0E0,  0x5C3E, 0xF0C0,  0x0C3C, 0x11C0,
  974.         0x143C, 0x3C40,  0x09B8, 0x3880,  0x05C0, 0x7000,  0x00CF, 0x0400,
  975.         0x000C, 0x6000,
  976.         },
  977.     /*----- bitmap Boing, frame 5:  w = 32, h = 25 ------ */
  978.         {
  979.         0x0026, 0x2000,  0x00FC, 0x7400,  0x0187, 0x7200,  0x030F, 0x0100,
  980.         0x0E0F, 0x0E80,  0x319F, 0x0E00,  0x23C6, 0x0F30,  0x63C1, 0xCF30,
  981.         0x4781, 0xF310,  0x0783, 0xE0D0,  0x7383, 0xE0E0,  0x70C3, 0xE0E0,
  982.         0x70F9, 0xE1E0,  0x70F8, 0x21E0,  0x70F8, 0x3FE0,  0x91F0, 0x3E38,
  983.         0x4FF0, 0x7C30,  0x4E10, 0x7C60,  0x4E0F, 0x7860,  0x2E1F, 0x08C0,
  984.         0x0E1E, 0x0E00,  0x049E, 0x1C80,  0x00E4, 0x3800,  0x00C7, 0x9000,
  985.         0x000E, 0x6000,
  986.         }
  987.     };
  988.  
  989. /* these structures contain the initialization data for the animation
  990. ** sequence.
  991. */
  992. NEWBOB newBoingBob =
  993.     {
  994.     NULL, BOING_WWIDTH, BOING_HEIGHT, BOING_DEPTH, 0x2, 0x0,
  995.     SAVEBACK | OVERLAY, 0, RBMDEPTH, 0,0,0,0,
  996.     };
  997. NEWANIMSEQ newBoingSeq =
  998.     {
  999.     NULL, (WORD *)boing3Image, boing3XTranses, boing3YTranses,
  1000.     boing3Times, boing3CRoutines, 0, BOING_COUNT, 0,
  1001.     };
  1002.  
  1003. /*-------------------------------------------------------------------------
  1004. ** setupBoing()
  1005. **
  1006. ** make a new animation object.  since all of the boing balls use the same
  1007. ** underlying data, the initalization structures are hard-coded into the
  1008. ** routine (newBoingBob and newBoingSeq.)
  1009. **
  1010. ** return a pointer to the object if successful, NULL if failure.
  1011. ** set a global error code on failure.
  1012. */
  1013. struct AnimOb *setupBoing(SHORT dbufing)
  1014. {
  1015. struct AnimOb   *bngOb;
  1016. struct AnimComp *bngComp;
  1017.  
  1018. if (NULL != (bngOb = AllocMem((LONG)sizeof(struct AnimOb), MEMF_CLEAR)))
  1019.     {
  1020.     newBoingBob.nb_DBuf    = dbufing;     /* double-buffer status  */
  1021.     newBoingSeq.nas_HeadOb = bngOb;       /* pass down head object */
  1022.  
  1023.     if (NULL != (bngComp = makeSeq(&newBoingBob, &newBoingSeq)))
  1024.         {
  1025.         bngOb->HeadComp = bngComp;  /* the head comp is the one that */
  1026.                                     /* is returned by makeSeq()      */
  1027.         return(bngOb);
  1028.         }
  1029.     FreeMem(bngOb, (LONG)sizeof(struct AnimOb));
  1030.     }
  1031. return_code = RETURN_WARN;
  1032. return(NULL);
  1033. }
  1034.  
  1035. /*-------------------------------------------------------------------------
  1036. ** runAnimation()
  1037. **
  1038. ** a simple message handling loop that also draws the successive frames.
  1039. */
  1040. VOID runAnimation(struct Window *win, SHORT dbufing,
  1041.                   struct AnimOb **animKey, struct BitMap **myBitMaps)
  1042. {
  1043. struct IntuiMessage  *intuiMsg;
  1044. WORD toggleFrame;
  1045.  
  1046. /* toggleFrame is used to keep track of which frame of the double buffered
  1047. ** screen we are currently displaying.  the variable must exist for the life
  1048. ** of the displayed objects, so it is defined here.
  1049. */
  1050. toggleFrame = 0;
  1051.  
  1052. /* end the loop on a CLOSEWINDOW event */
  1053. for (;;)
  1054.     {
  1055.     /* draw the gels, then check for messages.
  1056.     ** check the messages after each display so we get a quick response.
  1057.     */
  1058.     drawGels(win, animKey, dbufing, &toggleFrame, myBitMaps);
  1059.  
  1060.     /* quit on a control_c */
  1061.     if (SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  1062.         return;
  1063.  
  1064.     /* check for a closewindow event, die if found */
  1065.     while (intuiMsg = (struct IntuiMessage *)GetMsg(win->UserPort))
  1066.         {
  1067.         if (intuiMsg->Class == CLOSEWINDOW)
  1068.             {
  1069.             ReplyMsg((struct Message *)intuiMsg);
  1070.             return;
  1071.             }
  1072.         ReplyMsg((struct Message *)intuiMsg);
  1073.         }
  1074.     }
  1075. }
  1076.  
  1077. /*-------------------------------------------------------------------------
  1078. ** setupPlanes()
  1079. **
  1080. ** called only for double-buffered displays.
  1081. ** allocate and clear each bit-plane in a bitmap structure.
  1082. ** clean-up on failure.
  1083. */
  1084. LONG setupPlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height)
  1085. {
  1086. SHORT plane_num ;
  1087.  
  1088. for (plane_num = 0; plane_num < depth; plane_num++)
  1089.     {
  1090.     if (NULL != (bitMap->Planes[plane_num] =
  1091.                     (PLANEPTR)AllocRaster(width, height)))
  1092.         BltClear((APTR)(bitMap->Planes[plane_num]), (width / 8) * height, 1);
  1093.     else
  1094.         {
  1095.         freePlanes(bitMap, depth, width, height);
  1096.         return_code = RETURN_WARN;
  1097.         return(NULL);
  1098.         }
  1099.     }
  1100. return(TRUE);
  1101. }
  1102.  
  1103. /*-------------------------------------------------------------------------
  1104. ** setupBitMaps()
  1105. **
  1106. ** allocate the two bitmaps for a double-buffered display.
  1107. ** routine only called when the display is double-buffered.
  1108. */
  1109. struct BitMap **setupBitMaps(LONG depth, LONG width, LONG height)
  1110. {
  1111. static struct BitMap *myBitMaps[2];
  1112.  
  1113. /* allocate the two bit-map structures. these do not have to be in CHIP */
  1114. if (NULL != (myBitMaps[0] =
  1115.         (struct BitMap *)AllocMem((LONG)sizeof(struct BitMap), MEMF_CLEAR)))
  1116.     {
  1117.     if (NULL != (myBitMaps[1] =
  1118.         (struct BitMap *)AllocMem((LONG)sizeof(struct BitMap), MEMF_CLEAR)))
  1119.         {
  1120.         /* initialize the bit maps to the correct size. */
  1121.         InitBitMap(myBitMaps[0], (BYTE)depth, (SHORT)width, (SHORT)height);
  1122.         InitBitMap(myBitMaps[1], (BYTE)depth, (SHORT)width, (SHORT)height);
  1123.  
  1124.         /* allocate and initialize the bit-planes for the bit-maps. */
  1125.         if (NULL != setupPlanes(myBitMaps[0], depth, width, height))
  1126.             {
  1127.             if (NULL != setupPlanes(myBitMaps[1], depth, width, height))
  1128.                 return(myBitMaps);
  1129.  
  1130.             freePlanes(myBitMaps[0], depth, width, height);
  1131.             }
  1132.         FreeMem(myBitMaps[1], (LONG)sizeof(struct BitMap));
  1133.         }
  1134.     FreeMem(myBitMaps[0], (LONG)sizeof(struct BitMap));
  1135.     }
  1136. /* on failure, everything is freed and a global return code is set. */
  1137. return_code = RETURN_WARN;
  1138. return(NULL);
  1139. }
  1140.  
  1141. /*-------------------------------------------------------------------------
  1142. ** freePlanes()
  1143. **
  1144. ** free all of the bit-planes in a bit-map structure.
  1145. */
  1146. VOID freePlanes(struct BitMap *bitMap, LONG depth, LONG width, LONG height)
  1147. {
  1148. SHORT plane_num ;
  1149.  
  1150. for (plane_num = 0; plane_num < depth; plane_num++)
  1151.     {
  1152.     if (NULL != bitMap->Planes[plane_num])
  1153.         FreeRaster(bitMap->Planes[plane_num], (USHORT)width, (USHORT)height);
  1154.     }
  1155. }
  1156.  
  1157. /*-------------------------------------------------------------------------
  1158. ** freeBitMaps()
  1159. **
  1160. ** free the two bit-maps from the double buffered display.
  1161. ** the bit-planes are freed first, then the bit-map structures.
  1162. */
  1163. VOID freeBitMaps(struct BitMap **myBitMaps, LONG depth, LONG width, LONG height)
  1164. {
  1165. freePlanes(myBitMaps[0], depth, width, height);
  1166. freePlanes(myBitMaps[1], depth, width, height);
  1167.  
  1168. FreeMem(myBitMaps[0], (LONG)sizeof(struct BitMap));
  1169. FreeMem(myBitMaps[1], (LONG)sizeof(struct BitMap));
  1170. }
  1171.  
  1172. /*-------------------------------------------------------------------------
  1173. ** setupDisplay()
  1174. **
  1175. ** open the screen and the window for the display.
  1176. **
  1177. ** if using double buffered display, assume the bit-maps have been opened
  1178. ** and correctly set-up.
  1179. */
  1180. struct GelsInfo *setupDisplay(struct Window **win, SHORT dbufing,
  1181.                               struct BitMap **myBitMaps)
  1182. {
  1183. struct GelsInfo    *gInfo;
  1184. struct Screen      *screen;
  1185.  
  1186. /* if double-buffered, set-up the new screen structure for custom bit map */
  1187. if (dbufing)
  1188.     {
  1189.     ns.Type |= CUSTOMBITMAP;
  1190.     ns.CustomBitMap = myBitMaps[0];
  1191.     }
  1192.  
  1193. /* open everything.  check for failure. */
  1194. if ((screen = (struct Screen *)OpenScreen(&ns)) != NULL)
  1195.     {
  1196.     nw.Screen = screen;
  1197.     if ((*win = (struct Window *)OpenWindow(&nw)) != NULL)
  1198.         {
  1199.         if (dbufing)
  1200.             {
  1201.             /* we are double buffered.  set the rastport for it. */
  1202.             (*win)->WScreen->RastPort.Flags = DBUFFER;
  1203.  
  1204.             /* this copies the intuition display (close gadget) to the
  1205.             ** second bit-map so the display does not flash when we change
  1206.             ** between them.
  1207.             */
  1208.             (*win)->WScreen->RastPort.BitMap = myBitMaps[1];
  1209.             BltBitMapRastPort(myBitMaps[0], 0,0, &(*win)->WScreen->RastPort,
  1210.                         0,0, RBMWIDTH, RBMHEIGHT, 0xC0);
  1211.             (*win)->WScreen->RastPort.BitMap = myBitMaps[0];
  1212.             }
  1213.  
  1214.         /* ready the gel system for accepting objects
  1215.         ** this is only done once for each rastport in use.
  1216.         */
  1217.         if (NULL != (gInfo = setupGelSys(&(*win)->WScreen->RastPort, 0xFC)))
  1218.             return(gInfo);
  1219.  
  1220.         CloseWindow(*win);
  1221.         }
  1222.     CloseScreen(screen);
  1223.     }
  1224. /* on an error everything is cleaned-up, and a global return code is set. */
  1225. return_code = RETURN_WARN;
  1226. return(NULL);
  1227. }
  1228.  
  1229. /*-------------------------------------------------------------------------
  1230. ** drawGels()
  1231. **
  1232. ** handle the update of the display.  Animate the simulation and check for
  1233. ** collisions.  If the screen is double buffered, swap the bit map as
  1234. ** required.
  1235. */
  1236. VOID drawGels(struct Window *win, struct AnimOb **animKey, SHORT dbufing,
  1237.               WORD *toggleFrame, struct BitMap **myBitMaps)
  1238. {
  1239. /* do the required animation stuff.  you must sort both after the animate
  1240. ** call and after the collision call.
  1241. */
  1242. Animate((struct AnimOb *)animKey, &win->WScreen->RastPort);
  1243. SortGList(&win->WScreen->RastPort);
  1244.  
  1245. DoCollision(&win->WScreen->RastPort);
  1246. SortGList(&win->WScreen->RastPort);
  1247.  
  1248. /* toggle if double buffered */
  1249. if (dbufing)
  1250.     win->WScreen->ViewPort.RasInfo->BitMap = myBitMaps[*toggleFrame];
  1251.  
  1252. /* draw the new position of the gels into the screen. */
  1253. DrawGList(&win->WScreen->RastPort, &win->WScreen->ViewPort);
  1254.  
  1255. /* if using a double buffered display, you have a more complicated
  1256. ** update procedure.
  1257. **
  1258. ** if not, then simply use WaitTOF().
  1259. */
  1260. if (dbufing)
  1261.     {
  1262.     MakeScreen(win->WScreen);
  1263.     RethinkDisplay();
  1264.  
  1265.     *toggleFrame ^= 1;
  1266.     win->WScreen->RastPort.BitMap = myBitMaps[*toggleFrame];
  1267.     }
  1268. else
  1269.     WaitTOF();
  1270. }
  1271.  
  1272. /*-------------------------------------------------------------------------
  1273. ** bounceWall()
  1274. **
  1275. ** handle bouncing the animation objects off of the walls.
  1276. **
  1277. ** use __stdargs and __saveds because this routine is not directly called
  1278. ** by this program.  The call to DoCollision() causes a call back to
  1279. ** this routine when an animation object comes in contact with a wall.
  1280. ** __stdargs says the arguments are passed on the stack.
  1281. ** __saveds says to restore the data segment pointer on entry to the routine.
  1282. */
  1283. VOID __stdargs __saveds bounceWall(struct VSprite *vs1,LONG borderflags)
  1284. {
  1285. struct AnimOb *ob;
  1286.  
  1287. /* get a pointer to the object from the sprite pointer. */
  1288. ob = vs1->VSBob->BobComp->HeadOb;
  1289.  
  1290. /* check for hits and act apropriately.
  1291. ** for right and left, reverse the x velocity if the object is moving
  1292. ** towards the wall (it may have already reversed but still be in contact
  1293. ** with the wall.)
  1294. ** for the bottom and top you also have to subtract out the velocity.
  1295. */
  1296. if (((borderflags & RIGHTHIT) && (ob->XVel > 0)) ||
  1297.     ((borderflags & LEFTHIT) && (ob->XVel < 0)))
  1298.     ob->XVel = -(ob->XVel);
  1299. else if (((borderflags & TOPHIT) && (ob->YVel < 0)) ||
  1300.          ((borderflags & BOTTOMHIT) && (ob->YVel > 0)))
  1301.     {
  1302.     ob->YVel -= ob->YAccel;
  1303.     ob->YVel = -(ob->YVel);
  1304.     }
  1305. }
  1306.  
  1307. /*-------------------------------------------------------------------------
  1308. ** hit_routine()
  1309. **
  1310. ** handle the collision between two animation objects.
  1311. ** this routine simulates objects bouncing off of each other.
  1312. ** this does not do a very good job of it, it does not take into account
  1313. ** the angle of the collision or real physics.
  1314. ** if anyone wants to fix it, please feel free.
  1315. **
  1316. ** use __stdargs and __saveds because this routine is not directly called
  1317. ** by this program.  The call to DoCollision() causes a call back to
  1318. ** this routine when two animation objects overlap.
  1319. ** __stdargs says the arguments are passed on the stack.
  1320. ** __saveds says to restore the data segment pointer on entry to the routine.
  1321. */
  1322. VOID __stdargs __saveds hit_routine(struct VSprite *vs1,struct VSprite *vs2)
  1323. {
  1324. LONG vel1, vel2;
  1325.  
  1326. /* check that the bob is not being removed!  This is due to a 1.3 bug
  1327. ** where all bobs are tested for collision, even the ones that are in
  1328. ** the process of being removed.  See text for more information.
  1329. **
  1330. ** bobs are moved to a very large negative position as they are being
  1331. ** removed.  if the BOBSAWAY flag is set, then both bobs in the collision
  1332. ** are in the process of being removed--don't do anything in the collision
  1333. ** routine.
  1334. */
  1335. if (!(vs1->VSBob->Flags & BOBSAWAY))
  1336.     {
  1337.     /* cache the velocity values
  1338.     ** Do the X values first (order is not important.)
  1339.     */
  1340.     vel1 = vs1->VSBob->BobComp->HeadOb->XVel;
  1341.     vel2 = vs2->VSBob->BobComp->HeadOb->XVel;
  1342.  
  1343.     /* if the two objects are moving in the opposite direction (X component)
  1344.     ** then negate the velocities.
  1345.     ** else swap the velocities.
  1346.     */
  1347.     if (((vel1 > 0) && (vel2 < 0)) || ((vel1 < 0) && (vel2 > 0)))
  1348.         {
  1349.         vs1->VSBob->BobComp->HeadOb->XVel = -vel1;
  1350.         vs2->VSBob->BobComp->HeadOb->XVel = -vel2;
  1351.         }
  1352.     else
  1353.         {
  1354.         vs1->VSBob->BobComp->HeadOb->XVel = vel2;
  1355.         vs2->VSBob->BobComp->HeadOb->XVel = vel1;
  1356.         }
  1357.  
  1358.     /* cache the velocity values
  1359.     ** Do the Y values second (order is not important.)
  1360.     */
  1361.     vel1 = vs1->VSBob->BobComp->HeadOb->YVel;
  1362.     vel2 = vs2->VSBob->BobComp->HeadOb->YVel;
  1363.  
  1364.     /* if the two objects are moving in the opposite direction (Y component)
  1365.     ** then negate the velocities.
  1366.     ** else swap the velocities.
  1367.     */
  1368.     if (((vel1 > 0) && (vel2 < 0)) || ((vel1 < 0) && (vel2 > 0)))
  1369.         {
  1370.         vs1->VSBob->BobComp->HeadOb->YVel = -vel1;
  1371.         vs2->VSBob->BobComp->HeadOb->YVel = -vel2;
  1372.         }
  1373.     else
  1374.         {
  1375.         vs1->VSBob->BobComp->HeadOb->YVel = vel2;
  1376.         vs2->VSBob->BobComp->HeadOb->YVel = vel1;
  1377.         }
  1378.     }
  1379. }
  1380.  
  1381. /*-------------------------------------------------------------------------
  1382. ** main routine
  1383. **
  1384. ** run a double buffered display if the user puts any arguments on the
  1385. ** command line.
  1386. **
  1387. ** open libraries, set-up the display, set-up the animation system and
  1388. ** the objects, set-up collisions between objects and against walls,
  1389. ** and run the thing.
  1390. **
  1391. ** clean-up and close resources when done.
  1392. */
  1393. VOID main(int argc, char **argv)
  1394. {
  1395. struct BitMap   **myBitMaps;
  1396. struct AnimOb    *boingOb;
  1397. struct AnimOb    *boing2Ob;
  1398. struct AnimOb    *boing3Ob;
  1399. struct Window    *win;
  1400. struct Screen    *screen;
  1401. struct GelsInfo  *gInfo;
  1402. struct AnimOb    *animKey;
  1403. SHORT dbufing;
  1404.  
  1405. return_code = RETURN_OK;
  1406.  
  1407. /* if any arguments, use double-buffering */
  1408. if (argc > 1)
  1409.     dbufing = 1;
  1410. else
  1411.     dbufing = 0;
  1412.  
  1413. /* open required libraries */
  1414. if (NULL == (IntuitionBase = (struct IntuitionBase *)
  1415.         OpenLibrary("intuition.library", 33L)))
  1416.     return_code = RETURN_FAIL;
  1417. else
  1418.     {
  1419.     if (NULL == (GfxBase = (struct GfxBase *)
  1420.             OpenLibrary("graphics.library", 33L)))
  1421.         return_code = RETURN_FAIL;
  1422.     else
  1423.         {
  1424.         /* note that setupBitMaps() will only be called if
  1425.         ** we are double buffering
  1426.         */
  1427.         if ((!dbufing) ||
  1428.             (NULL != (myBitMaps=setupBitMaps(RBMDEPTH,RBMWIDTH,RBMHEIGHT))))
  1429.             {
  1430.             if (NULL != (gInfo = setupDisplay(&win,dbufing,myBitMaps)))
  1431.                 {
  1432.                 /* you have to initialize the animation key
  1433.                 ** before you use it.
  1434.                 */
  1435.                 InitAnimate(&animKey);
  1436.  
  1437.                 /* set-up the first boing ball.
  1438.                 ** all of these use the same data, hard coded into setupBoing().
  1439.                 ** change the color by changing PlanePick.
  1440.                 ** set the ID of the ball (MeMask) to BOING_1.
  1441.                 ** HitMask = 0xFF means that it will collide with everything.
  1442.                  */
  1443.                 newBoingBob.nb_PlanePick = 0x2;
  1444.                 newBoingBob.nb_MeMask    = 1L<<BOING_1;
  1445.                 newBoingBob.nb_HitMask   = 0xFF;
  1446.                 if (NULL != (boingOb = setupBoing(dbufing)))
  1447.                     {
  1448.                     /* pick an initial position, velocity and acceleration
  1449.                     ** and add the object to the system.  NOTE that the
  1450.                     ** Y-velocity and X-acceleration are not set (they default
  1451.                     ** to zero.)  This means that the objects will maintain
  1452.                     ** a constant movement to the left or right, and will
  1453.                     ** rely on the Y accelleration for the downward movement.
  1454.                     ** The collision routines change these values, producing
  1455.                     ** bouncing off of walls and other objects.
  1456.                     **
  1457.                     ** NOTE:  ANFRACSIZE is a value that shifts animation
  1458.                     ** constants past an internal decimal point.  If you
  1459.                     ** do not do this, then the values will only be some
  1460.                     ** fraction of what you expect.  See the Rom Kernel
  1461.                     ** Manual:  Libraries and Devices.
  1462.                     */
  1463.                     boingOb->AnY    = 10 << ANFRACSIZE;
  1464.                     boingOb->AnX    = 250 << ANFRACSIZE;
  1465.                     boingOb->XVel   = -(4 << ANFRACSIZE);
  1466.                     boingOb->YAccel = 70;
  1467.                     AddAnimOb(boingOb, (APTR)&animKey,
  1468.                                 &win->WScreen->RastPort);
  1469.  
  1470.                     /* do the second object--see above comments. */
  1471.                     newBoingBob.nb_PlanePick = 0x1;
  1472.                     newBoingBob.nb_MeMask    = 1L<<BOING_2;
  1473.                     newBoingBob.nb_HitMask   = 0xFF;
  1474.                     if (NULL != (boing2Ob = setupBoing(dbufing)))
  1475.                         {
  1476.                         boing2Ob->AnY    = 50 << ANFRACSIZE;
  1477.                         boing2Ob->AnX    = 50 << ANFRACSIZE;
  1478.                         boing2Ob->XVel   = 3 << ANFRACSIZE;
  1479.                         boing2Ob->YAccel = 70;
  1480.                         AddAnimOb(boing2Ob, (APTR)&animKey,
  1481.                                 &win->WScreen->RastPort);
  1482.  
  1483.                         /* do the second object--see above comments.
  1484.                         ** here we also use PlaneOnOff to change the color.
  1485.                         */
  1486.                         newBoingBob.nb_PlanePick = 0x1;
  1487.                         newBoingBob.nb_PlaneOnOff= 0x2;
  1488.                         newBoingBob.nb_MeMask    = 1L<<BOING_3;
  1489.                         newBoingBob.nb_HitMask   = 0xFF;
  1490.                         if (NULL != (boing3Ob = setupBoing(dbufing)))
  1491.                             {
  1492.                             boing3Ob->AnY    = 80 << ANFRACSIZE;
  1493.                             boing3Ob->AnX    = 150<< ANFRACSIZE;
  1494.                             boing3Ob->XVel   = 2 << ANFRACSIZE;
  1495.                             boing3Ob->YAccel = 70;
  1496.                             AddAnimOb(boing3Ob, (APTR)&animKey,
  1497.                                     &win->WScreen->RastPort);
  1498.  
  1499.                             /* set up the collisions between boing balls.
  1500.                             ** NOTE that they all call the same routine.
  1501.                             */
  1502.                             SetCollision(BOING_1,hit_routine,gInfo);
  1503.                             SetCollision(BOING_2,hit_routine,gInfo);
  1504.                             SetCollision(BOING_3,hit_routine,gInfo);
  1505.  
  1506.                             /* set the collisions with the walls. */
  1507.                             SetCollision(BORDERHIT,bounceWall,gInfo);
  1508.  
  1509.                             /* everything set-up...run the animation. */
  1510.                             runAnimation(win, dbufing, &animKey, myBitMaps);
  1511.  
  1512.                             /* done...
  1513.                             ** free-up everything and clean up the mess.
  1514.                              */
  1515.                             freeOb(boing3Ob, RBMDEPTH);
  1516.                             }
  1517.                         freeOb(boing2Ob, RBMDEPTH);
  1518.                         }
  1519.                     freeOb(boingOb, RBMDEPTH);
  1520.                     }
  1521.  
  1522.                 cleanupGelSys(gInfo, &win->WScreen->RastPort);
  1523.                 screen = win->WScreen;
  1524.                 CloseWindow(win);
  1525.                 CloseScreen(screen);
  1526.                 }
  1527.  
  1528.             if (dbufing)
  1529.                 freeBitMaps(myBitMaps, RBMDEPTH, RBMWIDTH, RBMHEIGHT);
  1530.             }
  1531.         CloseLibrary((struct Library *)GfxBase);
  1532.         }
  1533.     CloseLibrary((struct Library *)IntuitionBase);
  1534.     }
  1535.  
  1536. /* return the global return code to the system. */
  1537. exit(return_code);
  1538. }
  1539.